package top.canyue.word_range_service.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.nio.charset.StandardCharsets;

/**
 * redis配置类
 */

@Configuration
public class RedisConfig {

    /**
     * 配置Redis序列化
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);

        Jackson2JsonRedisSerializer jacksonSerializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域，field,get和set,以及修饰符范围，ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型，类必须是非final修饰的，final修饰的类，比如String,Integer等会抛出异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        // 忽略无法被序列化的属性，因为我们这里密码在User里面是passwordHash，而LoginUser中有getPassword方法
        // jacksonSerializer会尝试序列化所有getter方法对应的属性，当然，这里没有！！
        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        jacksonSerializer.setObjectMapper(om);

        // 这里可以添加一些自定义的序列化配置，例如日期格式等
        SerializeConfig serializeConfig = new SerializeConfig();

        // 设置值（value）的序列化方式
        template.setValueSerializer(jacksonSerializer);
        // 设置键（key）的序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        // 设置Hash类型key的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        // 设置Hash类型value的序列化方式
        template.setHashValueSerializer(jacksonSerializer);
        // 设置默认的序列化方式（可选，如果不设置，则默认使用JDK序列化）
        template.setDefaultSerializer(jacksonSerializer);

        return template;
    }

    @Bean
    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForValue();
    }

    // FastJsonRedisSerializer类定义
    public static class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
        private Class<T> type;

        static {
            ParserConfig.getGlobalInstance().addAccept("dto.LoginUser");
            ParserConfig.getGlobalInstance().addAccept("top.canyue.word_range_service.pojo.dto.LoginUser");
        }

        public FastJsonRedisSerializer(Class<T> type) {
            this.type = type;
        }

        @Override
        public byte[] serialize(T t) throws SerializationException {
            if (t == null) {
                return new byte[0];
            }
            return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8);
        }

        @Override
        public T deserialize(byte[] bytes) throws SerializationException {
            if (bytes == null || bytes.length <= 0) {
                return null;
            }
            String str = new String(bytes, StandardCharsets.UTF_8);
            return JSON.parseObject(str, type);
        }
    }
}
